/*
 * Main.java
 *
 * Created on April 22, 2007, 10:03 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.xeerkat.agent.tools;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.DateFormat;
import java.util.Date;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import org.restlet.util.Resolver;
import org.xeerkat.agent.*;
import org.xeerkat.agent.services.ServiceRegistry;
import org.xeerkat.xmpp.ID;

/**
 *
 * @author alex
 */
public class Main
{
   
static String fineLog =
"handlers= java.util.logging.ConsoleHandler\n"+
".level= FINE\n"+
"java.util.logging.ConsoleHandler.level = FINE\n"+
"java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter\n";
;
static String finerLog =
"handlers= java.util.logging.ConsoleHandler\n"+
".level= FINER\n"+
"java.util.logging.ConsoleHandler.level = FINER\n"+
"java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter\n";
;
static String finestLog =
"handlers= java.util.logging.ConsoleHandler\n"+
".level= FINEST\n"+
"java.util.logging.ConsoleHandler.level = FINEST\n"+
"java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter\n";
;
   static class DebugHandler extends Handler {
      public void publish(LogRecord record) {
         if (record.getLevel().intValue()<=Level.FINE.intValue()) {
            DateFormat format = DateFormat.getDateTimeInstance();
            String dateTime = format.format(new Date(record.getMillis()));
            System.err.println(dateTime+" "+record.getSourceClassName()+" "+record.getSourceMethodName());
            System.err.println(record.getLevel()+": "+record.getMessage());
         }
      }
      
      public void flush() {
         
      }
      
      public void close() {
         
      }
   }
   
   public static void main(String [] args)
   {
      try {
         Main main = new Main(args);
         main.init();
         main.start();
      } catch (Exception ex) {
         ex.printStackTrace();
         System.exit(1);
      }
   }
   
   AgentComponent agent;
   File confFile;
   URI location;
   String sender;
   String password;
   URI serviceLocation;
   
   /** Creates a new instance of Main */
   public Main(String[] args)
   {
      int argIndex = 0;
      Level logLevel = Level.INFO;
      while (argIndex < args.length && args[argIndex].charAt(0) == '-') {
         String name = args[argIndex].substring(1);
         argIndex++;
         if (argIndex == args.length) {
            throw new RuntimeException("The argument " + args[argIndex] + " requires an argument.");
         }
         if (name.equals("l") || name.equals("-level")) {
            if (args[argIndex].equals("info")) {
               logLevel = Level.INFO;
            } else if (args[argIndex].equals("fine")) {
               logLevel = Level.FINE;
            } else if (args[argIndex].equals("finer")) {
               logLevel = Level.FINER;
            } else if (args[argIndex].equals("finest")) {
               logLevel = Level.FINEST;
            } else if (args[argIndex].equals("config")) {
               logLevel = Level.CONFIG;
            }
         }
         argIndex++;
      }
      Logger xlog = Logger.getLogger("org.xeerkat");
      xlog.setLevel(logLevel);
      xlog.addHandler(new DebugHandler());
      
      if (logLevel==Level.FINE) {
         try {
            LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(fineLog.getBytes()));
         } catch (java.io.IOException ex) {
            ex.printStackTrace();
         }
      } else if (logLevel==Level.FINER) {
         try {
            LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(finerLog.getBytes()));
         } catch (java.io.IOException ex) {
            ex.printStackTrace();
         }
      } else if (logLevel==Level.FINEST) {
         try {
            LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(finestLog.getBytes()));
         } catch (java.io.IOException ex) {
            ex.printStackTrace();
         }

      }
      int argCount = args.length - argIndex;
      if (argCount!=1 && argCount!=2 && argCount!=3) {
         throw new RuntimeException(Main.class.getName()+" ( agent-conf-xml | from-id password {service-xml} )");
      }
      xlog.info("Version "+AgentContext.class.getPackage().getImplementationVersion());
      location = null;
      confFile = null;
      try {
         if (argCount==1) {
            if (args[0].charAt(0)=='!') {
               location = new URI(args[argIndex].substring(1));
            } else {
               confFile = new File(args[argIndex]);
               location = confFile.toURI();
            }
            sender = null;
            password = null;
         } else {
            sender = args[argIndex];
            password = args[argIndex+1];
            if (argCount>2) {
               if (args[2].charAt(0)=='!') {
                  serviceLocation = new URI(args[argIndex+2].substring(1));
               } else {
                  serviceLocation = (new File(args[argIndex+2])).toURI();
               }
            }
         }
      } catch (URISyntaxException ex) {
         throw new RuntimeException("Cannot construct URI: "+ex.getMessage(),ex);
      }
   }
   
   public void init() {
      
      try {
         Configuration conf = null;
         File current = confFile==null ? new File(".") : confFile.getParentFile();
         if (location!=null) {
            conf = new Configuration();
            conf.load(location);
         } else {
            if (sender.indexOf('/')<0) {
               sender = sender + "/agent";
            }
            ID senderId = new ID(sender);
            senderId.setPassword(password);
            
            conf = new Configuration();
            
            Configuration.Agent agent = conf.createAgent(senderId);
            if (serviceLocation!=null) {
               ServiceRegistry registry = new ServiceRegistry(location.toString(),serviceLocation);
               registry.load();
               agent.getServiceRegistries().add(registry);
            }
            
            conf.getInterfaces().add(new Configuration.Interface("*",8080,false));
            conf.getHosts().add(new Configuration.Host("*"));
         }
         
         final File runDir = current;
         final Configuration agentConf = conf;
         Resolver<String> environment = new Resolver<String>() {
            public String resolve(String name) {
               if (name.equals("install.dir")) {
                  return runDir.getAbsolutePath();
               } else if (name.equals("install.href")) {
                  return runDir.getAbsoluteFile().toURI().toString();
               } else {
                  return null;
               }
            }
         };
         agent = new AgentComponent(agentConf);
         final Logger log = agent.getLogger();
         agent.getUpgradeListeners().add(new AgentManager(agent,environment) {
            
            protected boolean authorize(ID to,ID from,String method,String username,String password)
            {
               return username.equals(agentConf.getUsername()) && password.equals(agentConf.getPassword());
            }
         });
      } catch (Exception ex) {
         ex.printStackTrace();
      }
   }
   
   public void start() 
      throws Exception
   {
      agent.start();
   }
   
   public void stop() 
      throws Exception
   {
      agent.stop();
   }
   
}
